﻿using System;

namespace Bouyei.NetworkSniffer
{
    public static class TypeConvert
    {
        /// <summary>
        /// 获取当前操作系统的字节序
        /// </summary>
        public static bool isBigEndian { get; private set; }

        static TypeConvert()
        {
            isBigEndian = CheckSysIsBigEndian();
        }
 
        public static bool CheckSysIsBigEndian()
        {
            UInt16 flag = 0x4321;
            if ((byte)(flag >> 8) == 0x43)
                return false;
            else return true;
        }

        /// <summary>
        /// 网络字节序转换为主机字节序
        /// 网络字节序为大端字节序
        /// </summary>
        /// <param name="network"></param>
        /// <returns></returns>
        public static ushort ToHostOrder(this ushort network)
        {
            if (isBigEndian) return network;
             
            return (ushort)(((network & 0xff) << 8) | ((network >> 8) & 0xff));
        }

        public static short ToHostOrder(this short network)
        {
            if (isBigEndian) return network;
           
            return (short)(((network & 0xff) << 8) | ((network >> 8) & 0xff));
        }

        public static uint ToHostOrder(this uint network)
        {
            if (isBigEndian) return network;
          
            return (uint)(
                ((ToHostOrder((ushort)network) & 0xffff) << 0x10)
                | (ToHostOrder((ushort)(network >> 0x10)) & 0xffff)
                );
        }

        public static int ToHostOrder(this int network)
        {
            if (isBigEndian) return network;
        
            return (int)(
                ((ToHostOrder((short)network) & 0xffff) << 0x10)
                | (ToHostOrder((short)(network >> 0x10)) & 0xffff)
                );
        }

        public static ulong ToHostOrder(this ulong network)
        {
            if (isBigEndian) return network;

            return (ulong)(
                ((ToHostOrder((uint)network) & 0xffffffffL) << 0x20)
                | (ToHostOrder((uint)(network >> 0x20)) & 0xffffffffL)
                );
        }

        public static long ToHostOrder(this long network)
        {
            if (isBigEndian) return network;

            return (long)(
                ((ToHostOrder((int)network) & 0xffffffffL) << 0x20)
                | (ToHostOrder((int)(network >> 0x20)) & 0xffffffffL)
                );
        }

        public static ushort ToUInt16HostOrder(this byte[] network, int offset)
        {
            if (!isBigEndian)
            {
                return (ushort)(((ushort)network[offset] << 8)
                | ((ushort)network[offset + 1]));
            }

            return (ushort)(network[offset]
                | (ushort)(network[offset + 1] << 8));
        }

        public static uint ToUInt32HostOrder(this byte[] network, int offset)
        {
            if (isBigEndian)
            {
                return (((uint)network[offset] << 24)
                   | ((uint)network[offset + 1] << 16)
                   | ((uint)network[offset + 2] << 8)
                   | (uint)network[offset + 3]);
            }

            return ((uint)network[offset]
                   | ((uint)network[offset + 1] << 8)
                   | ((uint)network[offset + 2] << 16)
                   | (uint)(network[offset + 3] << 24));
        }

        public static ulong ToUInt64HostOrder(this byte[] network, int offset)
        {
            if (!isBigEndian)
            {
                return (((ulong)network[offset] << 56)
                  | ((ulong)network[offset + 1] << 48)
                  | ((ulong)network[offset + 2] << 40)
                  | ((ulong)network[offset + 3] << 32)
                  | ((ulong)network[offset + 4] << 24)
                  | ((ulong)network[offset + 5] << 16)
                  | ((ulong)network[offset + 6] << 8)
                  | (ulong)network[offset + 7]);
            }

            return ((ulong)network[offset]
                 | ((ulong)network[offset + 1] << 8)
                 | ((ulong)network[offset + 2] << 16)
                 | ((ulong)network[offset + 3] << 24)
                 | ((ulong)network[offset + 4] << 32)
                 | ((ulong)network[offset + 5] << 40)
                 | ((ulong)network[offset + 6] << 48)
                 | ((ulong)network[offset + 7] << 56));
        }
    }
}
